﻿using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Red.Controls.Extensions;
using Red.Core;
using Red.Core.Extensions;
using P4 = Red.Core.Perforce;

namespace Red.Controls
{
    public partial class SourceControlButton : UserControl
    {
        #region Private Data
        
        private string _resourcePath;
        private DepotInfo _depotInfo;

        private Canvas _locked;
        private Canvas _unlocked;
        private Canvas _warning;
        private Canvas _critical;
        private Canvas _add;
        private Canvas _local;

        private Brush _checkedIn;

        #endregion Private Data

        #region Dependency Properties

        public static readonly DependencyProperty IconProperty = DependencyProperty.Register( "Icon", typeof( Canvas ), typeof( SourceControlButton ) );
        public static readonly DependencyProperty CircleColourProperty = DependencyProperty.Register( "CircleColour", typeof( Brush ), typeof( SourceControlButton ) );

        #endregion Dependency Properties

        #region Private Properties

        private Canvas Icon
        {
            get { return (Canvas)GetValue( IconProperty ); }
            set { SetValue( IconProperty, value ); }
        }

        private Brush CircleColour
        {
            get { return (Brush)GetValue( CircleColourProperty ); }
            set { SetValue( CircleColourProperty, value ); }
        }

        private new string ToolTip
        {
            set { base.ToolTip = TooltipExtension.GetTooltip( @"Red.Controls", value ); }
        }

        private SourceControl.UIHelper UIHelper { get; set; } = new SourceControl.UIHelper();
        private Core.SourceControl.Monitor Monitor { get; set; } = new Core.SourceControl.Monitor();
        private P4.FileStatus Status { get; set; }
        private FileInfo LocalStatus { get; set; }

        #endregion Private Properties

        #region Public Properties

        public string ResourcePath
        {
            get
            {
                return _resourcePath;
            }
            set
            {
                // It's unlikely that a source control button will be switched between files, but better safe than sorry
                Monitor.Files.Remove( value );

                _resourcePath = value;
                UIHelper.File = value;
                Monitor.Files.Add( value );
            }
        }

        public DepotInfo DepotInfo
        {
            get
            {
                return _depotInfo;
            }
            set
            {
                _depotInfo = value;
                UIHelper.SourceControl = value.SourceControl;
                Monitor.SourceControl = value.SourceControl;

                RefreshStatus();
            }
        }

        #endregion Public Properties

        #region C-Tor

        public SourceControlButton()
        {
            InitializeComponent();
            
            UIHelper.Owner = Window.GetWindow( this );
            Monitor.OperationFinished += Monitor_OperationFinished;

            Unloaded += SourceControlButton_Unloaded;

            _locked = (Canvas)FindResource( @"appbar_lock" );
            _unlocked = (Canvas)FindResource( @"appbar_unlock" );
            _warning = (Canvas)FindResource( @"warning" );
            _critical = (Canvas)FindResource( @"sourcecontrol_critical" );
            _add = (Canvas)FindResource( @"appbar_add" );
            _local = (Canvas)FindResource( @"appbar_alien" );
            _checkedIn = (Brush)FindResource( @"GrayBrush7" );

            Icon = _locked;
        }

        #endregion C-Tor

        #region Private Methods

        private void RefreshStatus( P4.FileStatus sourceControlStatus )
        {
            Status = sourceControlStatus;
            LocalStatus = new FileInfo( ResourcePath );

            if ( !LocalStatus.IsReadOnly && ( Status.CheckedOutByOthers ) )
            {
                Icon = _warning;
                CircleColour = Brushes.OrangeRed;
                ToolTip = "SourceControl.Button.Status.LocalEditCheckedOutByOthers";
            }
            else if ( !LocalStatus.IsReadOnly && !Status.IsLatestRevision )
            {
                Icon = _critical;
                CircleColour = Brushes.Black;
                ToolTip = "SourceControl.Button.Status.LocalEditNotLatestEdited";
            }
            else if ( !Status.IsLatestRevision )
            {
                Icon = _locked;
                CircleColour = Brushes.CornflowerBlue;
                ToolTip = "SourceControl.Button.Status.NotLatest";
            }
            else if ( Status.CheckedOutByMe )
            {
                Icon = _unlocked;
                CircleColour = Brushes.LawnGreen;
                ToolTip = "SourceControl.Button.Status.CheckedOut";
            }
            else if ( Status.IsMarkedForAdd )
            {
                Icon = _add;
                CircleColour = Brushes.LawnGreen;
                ToolTip = "SourceControl.Button.Status.MarkedForAdd";
            }
            else if ( Status.NotUnderSourceControl )
            {
                Icon = _local;
                CircleColour = Brushes.LawnGreen;
                ToolTip = "SourceControl.Button.Status.Local";
            }
            else if ( !LocalStatus.IsReadOnly )
            {
                Icon = _unlocked;
                CircleColour = Brushes.Gold;
                ToolTip = "SourceControl.Button.Status.LocalEditNotCheckedOut";
            }
            else
            {
                Icon = _locked;
                CircleColour = _checkedIn;
                ToolTip = "SourceControl.Button.Status.CheckedIn";
            }
        }

        private void RefreshStatus()
        {
            if ( DepotInfo != null && ResourcePath != null )
            {
                P4.FileStatus sourceControlStatus = DepotInfo.SourceControl.GetFileStatus( ResourcePath );
                RefreshStatus( sourceControlStatus );
            }
        }
        
        private async void Checkout()
        {
            await UIHelper.Checkout();
        }

        private async void Revert()
        {
            await UIHelper.Revert();
        }

        private async void MarkForAdd()
        {
            await UIHelper.MarkForAdd();
        }

        private async void GetLatest()
        {
            await UIHelper.GetLatest();
        }

        #endregion Private Methods

        #region Event Handlers

        private void Button_Click( object sender, RoutedEventArgs e )
        {
            Button button = (Button)sender;

            SourceControl.InteractionTray tray = new SourceControl.InteractionTray()
            {
                ButtonHeight = (int)button.ActualHeight,
                ButtonWidth = (int)button.ActualWidth
            };

            tray.SetPositionRelativeTo( button );

            tray.AddButton( "appbar_refresh", RefreshStatus, "SourceControl.Button.Refresh" );

            if ( !Status.NotUnderSourceControl && !Status.IsMarkedForAdd )
            {
                tray.AddButton( "sourcecontrol_getlatest", GetLatest, "SourceControl.Button.GetLatest" );

                if ( !Status.CheckedOutByMe && !Status.IsMarkedForAdd )
                {
                    tray.AddButton( "sourcecontrol_checkout", Checkout, "SourceControl.Button.CheckOut" );
                }
            }
            else if ( Status.NotUnderSourceControl && !Status.IsMarkedForAdd )
            {
                tray.AddButton( "sourcecontrol_markforadd", MarkForAdd, "SourceControl.Button.MarkForAdd" );
            }

            if ( Status.CheckedOutByMe || Status.IsMarkedForAdd )
            {
                tray.AddButton( "sourcecontrol_revert", Revert, "SourceControl.Button.Revert" );
            }

            tray.Show();
        }

        private void Monitor_OperationFinished( string file, Perforce.P4.FileMetaData metadata )
        {
            P4.FileStatus status = DepotInfo.SourceControl.GetFileStatus( metadata );
            RefreshStatus( status );
        }

        private void SourceControlButton_Unloaded( object sender, RoutedEventArgs e )
        {
            // Make sure to perform the cleanup necessary that allows both the monitor
            // and this class to be garbage collected now that it is no longer used
            Monitor.Clear();
        }

        #endregion Event Handlers
    }
}
